package com.rickpan.service;

import com.rickpan.entity.FileInfo;
import com.rickpan.repository.FileInfoRepository;
import com.rickpan.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;

/**
 * 文件预览服务
 * 
 * @author RickPan Team
 * @since 2025-07-02
 */
@Service
public class FilePreviewService {

    @Autowired
    private FileInfoRepository fileInfoRepository;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private com.rickpan.storage.StorageService storageService;

    /**
     * 视频流媒体服务
     * 支持Range请求，实现视频分段加载
     * 
     * @param fileId 文件ID
     * @param userId 用户ID
     * @param rangeHeader Range请求头
     * @return 视频流响应
     */
    public ResponseEntity<Resource> streamVideo(Long fileId, Long userId, String rangeHeader) {
        try {
            // 验证文件权限
            FileInfo fileInfo = validateFileAccess(fileId, userId);
            
            // 检查是否是视频文件
            if (!isVideoFile(fileInfo.getMimeType())) {
                throw new BusinessException("文件不是视频格式");
            }
            
            // 智能检测文件存储位置
            Path localVideoPath = fileStorageService.getAbsolutePath(fileInfo.getFilePath());
            File localVideoFile = localVideoPath.toFile();
            boolean existsLocally = localVideoFile.exists();

            System.out.println("视频文件路径检查: 相对路径=" + fileInfo.getFilePath() +
                ", 本地路径=" + localVideoPath + ", 本地存在=" + existsLocally +
                ", 当前存储类型=" + storageService.getStorageType());

            if (existsLocally) {
                // 文件在本地存储中：支持 Range 请求
                long fileLength = localVideoFile.length();

                // 处理Range请求
                if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
                    return handleRangeRequest(localVideoFile, rangeHeader, fileLength, fileInfo);
                } else {
                    // 完整文件响应
                    return handleFullFileResponse(localVideoFile, fileInfo);
                }

            } else if ("minio".equals(storageService.getStorageType())) {
                // 文件在 MinIO 中：生成预签名 URL 并重定向
                // 注意：MinIO 预签名 URL 本身支持 Range 请求
                try {
                    String previewUrl = storageService.generatePreviewUrl(
                        fileInfo.getFilePath(),
                        java.time.Duration.ofHours(2) // 视频预览时间更长
                    );

                    System.out.println("使用MinIO预览视频，重定向到: " + previewUrl);

                    return ResponseEntity.status(HttpStatus.FOUND)
                            .header(HttpHeaders.LOCATION, previewUrl)
                            .build();

                } catch (Exception e) {
                    throw new BusinessException("视频文件不存在于MinIO中: " + e.getMessage());
                }
            } else {
                throw new BusinessException("视频文件不存在: " + localVideoPath);
            }
            
        } catch (Exception e) {
            System.err.println("视频流服务错误: " + e.getMessage());
            throw new BusinessException("视频流服务失败: " + e.getMessage());
        }
    }

    /**
     * 处理Range请求（分段传输）
     */
    private ResponseEntity<Resource> handleRangeRequest(File file, String rangeHeader, long fileLength, FileInfo fileInfo) {
        try {
            // 解析Range头：bytes=start-end
            String range = rangeHeader.substring(6); // 移除"bytes="
            String[] ranges = range.split("-");
            
            long start = 0;
            long end = fileLength - 1;
            
            if (ranges.length > 0 && !ranges[0].isEmpty()) {
                start = Long.parseLong(ranges[0]);
            }
            if (ranges.length > 1 && !ranges[1].isEmpty()) {
                end = Long.parseLong(ranges[1]);
            }
            
            // 确保范围有效
            if (start > end || start >= fileLength) {
                return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
                        .header(HttpHeaders.CONTENT_RANGE, "bytes */" + fileLength)
                        .build();
            }
            
            // 限制end不超过文件长度
            end = Math.min(end, fileLength - 1);
            long contentLength = end - start + 1;
            
            // 创建部分内容资源
            Resource resource = new PartialFileResource(file, start, contentLength);
            
            return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
                    .header(HttpHeaders.CONTENT_TYPE, fileInfo.getMimeType())
                    .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength))
                    .header(HttpHeaders.CONTENT_RANGE, "bytes " + start + "-" + end + "/" + fileLength)
                    .header(HttpHeaders.ACCEPT_RANGES, "bytes")
                    .body(resource);
                    
        } catch (Exception e) {
            throw new BusinessException("Range请求处理失败: " + e.getMessage());
        }
    }

    /**
     * 处理完整文件响应
     */
    private ResponseEntity<Resource> handleFullFileResponse(File file, FileInfo fileInfo) {
        Resource resource = new FileSystemResource(file);
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, fileInfo.getMimeType())
                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()))
                .header(HttpHeaders.ACCEPT_RANGES, "bytes")
                .body(resource);
    }

    /**
     * 图片预览（支持混合存储）
     */
    public ResponseEntity<Resource> previewImage(Long fileId, Long userId) {
        try {
            FileInfo fileInfo = validateFileAccess(fileId, userId);

            if (!isImageFile(fileInfo.getMimeType())) {
                throw new BusinessException("文件不是图片格式");
            }

            // 智能检测文件存储位置
            // 首先检查本地文件是否存在
            Path localImagePath = fileStorageService.getAbsolutePath(fileInfo.getFilePath());
            File localImageFile = localImagePath.toFile();
            boolean existsLocally = localImageFile.exists();

            System.out.println("图片文件路径检查: 相对路径=" + fileInfo.getFilePath() +
                ", 本地路径=" + localImagePath + ", 本地存在=" + existsLocally +
                ", 当前存储类型=" + storageService.getStorageType());

            if (existsLocally) {
                // 文件在本地存储中：直接返回本地文件
                System.out.println("使用本地存储预览图片: " + localImagePath);

                Resource resource = new FileSystemResource(localImageFile);

                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_TYPE, fileInfo.getMimeType())
                        .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(localImageFile.length()))
                        .body(resource);

            } else if ("minio".equals(storageService.getStorageType())) {
                // 文件可能在 MinIO 中：生成预签名 URL 并重定向
                try {
                    String previewUrl = storageService.generatePreviewUrl(
                        fileInfo.getFilePath(),
                        java.time.Duration.ofMinutes(30)
                    );

                    System.out.println("使用MinIO预览图片，重定向到: " + previewUrl);

                    // 返回重定向响应
                    return ResponseEntity.status(HttpStatus.FOUND)
                            .header(HttpHeaders.LOCATION, previewUrl)
                            .build();

                } catch (Exception e) {
                    System.out.println("MinIO预览失败: " + e.getMessage());
                    throw new BusinessException("图片文件不存在于MinIO中: " + e.getMessage());
                }
            } else {
                throw new BusinessException("图片文件不存在: " + localImagePath);
            }

        } catch (Exception e) {
            throw new BusinessException("图片预览失败: " + e.getMessage());
        }
    }

    /**
     * PDF预览（支持混合存储）
     */
    public ResponseEntity<Resource> previewPdf(Long fileId, Long userId) {
        try {
            FileInfo fileInfo = validateFileAccess(fileId, userId);

            if (!"application/pdf".equals(fileInfo.getMimeType())) {
                throw new BusinessException("文件不是PDF格式");
            }

            // 智能检测文件存储位置
            Path localPdfPath = fileStorageService.getAbsolutePath(fileInfo.getFilePath());
            File localPdfFile = localPdfPath.toFile();
            boolean existsLocally = localPdfFile.exists();

            System.out.println("PDF文件路径检查: 相对路径=" + fileInfo.getFilePath() +
                ", 本地路径=" + localPdfPath + ", 本地存在=" + existsLocally +
                ", 当前存储类型=" + storageService.getStorageType());

            if (existsLocally) {
                // 文件在本地存储中
                Resource resource = new FileSystemResource(localPdfFile);

                // 对中文文件名进行URL编码
                String encodedFilename = URLEncoder.encode(fileInfo.getOriginalName(), StandardCharsets.UTF_8)
                        .replaceAll("\\+", "%20");

                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_TYPE, "application/pdf")
                        .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(localPdfFile.length()))
                        .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''" + encodedFilename)
                        .body(resource);

            } else if ("minio".equals(storageService.getStorageType())) {
                // 文件可能在 MinIO 中：生成预签名 URL 并重定向
                try {
                    String previewUrl = storageService.generatePreviewUrl(
                        fileInfo.getFilePath(),
                        java.time.Duration.ofMinutes(30)
                    );

                    System.out.println("使用MinIO预览PDF，重定向到: " + previewUrl);

                    return ResponseEntity.status(HttpStatus.FOUND)
                            .header(HttpHeaders.LOCATION, previewUrl)
                            .build();

                } catch (Exception e) {
                    throw new BusinessException("PDF文件不存在于MinIO中: " + e.getMessage());
                }
            } else {
                throw new BusinessException("PDF文件不存在: " + localPdfPath);
            }
                    
        } catch (Exception e) {
            throw new BusinessException("PDF预览失败: " + e.getMessage());
        }
    }

    /**
     * 文档转HTML预览（DOC/DOCX）
     */
    public String convertDocumentToHtml(Long fileId, Long userId) {
        try {
            FileInfo fileInfo = validateFileAccess(fileId, userId);
            
            if (!isDocumentFile(fileInfo.getMimeType())) {
                throw new BusinessException("文件不是文档格式");
            }
            
            // 这里应该使用Apache POI或其他库来转换文档
            // 目前返回一个简单的HTML模板
            return generateDocumentPreviewHtml(fileInfo);
            
        } catch (Exception e) {
            throw new BusinessException("文档预览失败: " + e.getMessage());
        }
    }

    /**
     * 表格转JSON预览（XLS/XLSX）
     */
    public String convertSpreadsheetToJson(Long fileId, Long userId) {
        try {
            FileInfo fileInfo = validateFileAccess(fileId, userId);
            
            if (!isSpreadsheetFile(fileInfo.getMimeType())) {
                throw new BusinessException("文件不是表格格式");
            }
            
            // 这里应该使用Apache POI或EasyExcel来读取表格
            // 目前返回一个简单的JSON模板
            return generateSpreadsheetPreviewJson(fileInfo);
            
        } catch (Exception e) {
            throw new BusinessException("表格预览失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件预览信息
     */
    public String getPreviewInfo(Long fileId, Long userId) {
        try {
            FileInfo fileInfo = validateFileAccess(fileId, userId);
            
            return String.format(
                "{\"fileId\":%d,\"fileName\":\"%s\",\"mimeType\":\"%s\",\"fileSize\":%d,\"previewType\":\"%s\"}",
                fileInfo.getId(),
                fileInfo.getOriginalName(),
                fileInfo.getMimeType(),
                fileInfo.getFileSize(),
                getPreviewType(fileInfo.getMimeType())
            );
            
        } catch (Exception e) {
            throw new BusinessException("获取预览信息失败: " + e.getMessage());
        }
    }

    /**
     * 验证文件访问权限
     */
    private FileInfo validateFileAccess(Long fileId, Long userId) {
        System.out.println("验证文件访问权限: fileId=" + fileId + ", userId=" + userId);

        Optional<FileInfo> fileOpt = fileInfoRepository.findByIdAndOwnerIdAndIsDeletedFalse(fileId, userId);
        if (fileOpt.isEmpty()) {
            System.err.println("文件访问验证失败: fileId=" + fileId + ", userId=" + userId);

            // 尝试查找文件是否存在（不考虑用户权限）
            Optional<FileInfo> anyFileOpt = fileInfoRepository.findById(fileId);
            if (anyFileOpt.isEmpty()) {
                System.err.println("文件完全不存在: fileId=" + fileId);
                throw new BusinessException("文件不存在");
            } else {
                FileInfo file = anyFileOpt.get();
                System.err.println("文件存在但权限不匹配: fileId=" + fileId +
                    ", 文件所有者=" + file.getOwnerId() +
                    ", 当前用户=" + userId +
                    ", 是否删除=" + file.getIsDeleted());
                throw new BusinessException("无权限访问此文件");
            }
        }

        FileInfo fileInfo = fileOpt.get();
        System.out.println("文件访问验证成功: " + fileInfo.getOriginalName() +
            ", 路径=" + fileInfo.getFilePath());
        return fileInfo;
    }

    /**
     * 检查是否是视频文件
     */
    private boolean isVideoFile(String mimeType) {
        return mimeType != null && mimeType.startsWith("video/");
    }

    /**
     * 检查是否是图片文件
     */
    private boolean isImageFile(String mimeType) {
        return mimeType != null && mimeType.startsWith("image/");
    }

    /**
     * 检查是否是文档文件
     */
    private boolean isDocumentFile(String mimeType) {
        return mimeType != null && (
            mimeType.equals("application/msword") ||
            mimeType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
        );
    }

    /**
     * 检查是否是表格文件
     */
    private boolean isSpreadsheetFile(String mimeType) {
        return mimeType != null && (
            mimeType.equals("application/vnd.ms-excel") ||
            mimeType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        );
    }

    /**
     * 获取预览类型
     */
    private String getPreviewType(String mimeType) {
        if (isVideoFile(mimeType)) return "video";
        if (isImageFile(mimeType)) return "image";
        if (mimeType != null && mimeType.equals("application/pdf")) return "pdf";
        if (isDocumentFile(mimeType)) return "document";
        if (isSpreadsheetFile(mimeType)) return "spreadsheet";
        return "unsupported";
    }

    /**
     * 生成文档预览HTML
     */
    private String generateDocumentPreviewHtml(FileInfo fileInfo) {
        return String.format(
            "<html><head><title>%s</title></head><body>" +
            "<h1>文档预览</h1>" +
            "<p>文件名: %s</p>" +
            "<p>文件大小: %d 字节</p>" +
            "<p>注意: 完整的文档预览功能正在开发中...</p>" +
            "</body></html>",
            fileInfo.getOriginalName(),
            fileInfo.getOriginalName(),
            fileInfo.getFileSize()
        );
    }

    /**
     * 生成表格预览JSON
     */
    private String generateSpreadsheetPreviewJson(FileInfo fileInfo) {
        return String.format(
            "{\"fileName\":\"%s\",\"fileSize\":%d,\"sheets\":[{\"name\":\"Sheet1\",\"data\":[[\"示例数据\",\"正在开发中\"]]}],\"message\":\"完整的表格预览功能正在开发中...\"}",
            fileInfo.getOriginalName(),
            fileInfo.getFileSize()
        );
    }
}
